package com.eian.boot.helper;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;

import java.util.HashMap;
import java.util.Map;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

/**
 * Token管理工具
 *
 * <p>负责管理测试用户的登录Token，避免重复登录
 *
 * @author test
 */
@Slf4j
@Component
public class TokenManager {

    /**
     * 测试用户账号信息
     */
    private static final String ADMIN_USERNAME = "admin";
    private static final String ADMIN_PASSWORD = "admin123";
    private static final String MANAGER_USERNAME = "manager";
    private static final String MANAGER_PASSWORD = "manager123";
    private static final String USER_USERNAME = "user";
    private static final String USER_PASSWORD = "user123";
    /**
     * Token缓存
     * Key: 用户名
     * Value: Token
     */
    private final Map<String, String> tokenCache = new HashMap<>();

    /**
     * 获取超级管理员Token
     */
    public String getAdminToken(MockMvc mockMvc, ObjectMapper objectMapper) throws Exception {
        return getOrLoginToken(mockMvc, objectMapper, ADMIN_USERNAME, ADMIN_PASSWORD);
    }

    /**
     * 获取普通管理员Token
     */
    public String getManagerToken(MockMvc mockMvc, ObjectMapper objectMapper) throws Exception {
        return getOrLoginToken(mockMvc, objectMapper, MANAGER_USERNAME, MANAGER_PASSWORD);
    }

    /**
     * 获取普通用户Token
     */
    public String getUserToken(MockMvc mockMvc, ObjectMapper objectMapper) throws Exception {
        return getOrLoginToken(mockMvc, objectMapper, USER_USERNAME, USER_PASSWORD);
    }

    /**
     * 获取或登录Token
     *
     * @param username 用户名
     * @param password 密码
     * @return Token
     */
    public String getOrLoginToken(MockMvc mockMvc, ObjectMapper objectMapper, String username, String password) throws Exception {
        // 检查缓存
        if (tokenCache.containsKey(username)) {
            String cachedToken = tokenCache.get(username);
            log.debug("使用缓存的Token: {}", username);
            return cachedToken;
        }

        // 执行登录
        log.info("用户登录获取Token: {}", username);
        String token = performLogin(mockMvc, objectMapper, username, password);

        // 缓存Token
        tokenCache.put(username, token);

        return token;
    }

    /**
     * 执行登录操作
     */
    private String performLogin(MockMvc mockMvc, ObjectMapper objectMapper, String username, String password) throws Exception {
        Map<String, String> loginRequest = new HashMap<>();
        loginRequest.put("account", username);
        loginRequest.put("password", password);

        MvcResult result = mockMvc.perform(post("/auth/login")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(loginRequest)))
                .andExpect(status().isOk())
                .andReturn();

        String responseBody = result.getResponse().getContentAsString();
        JsonNode jsonNode = objectMapper.readTree(responseBody);

        // 从响应中提取token
        JsonNode dataNode = jsonNode.get("data");
        if (dataNode != null && dataNode.has("token")) {
            String token = dataNode.get("token").asText();
            log.info("登录成功，获取Token: {} -> {}", username, token);
            return token;
        }

        throw new RuntimeException("登录失败，无法获取Token: " + responseBody);
    }

    /**
     * 清除所有Token缓存
     */
    public void clearAllTokens() {
        tokenCache.clear();
        log.debug("清除所有Token缓存");
    }

    /**
     * 清除指定用户的Token
     */
    public void clearToken(String username) {
        tokenCache.remove(username);
        log.debug("清除Token缓存: {}", username);
    }
}

